import type {AxiosRequestConfig, Method} from 'axios'
import axios from 'axios'
import {ElLoading, ElMessageBox, ElNotification, type LoadingOptions} from 'element-plus'
import {refreshToken} from '/@/api/common'
import router from '/@/router/index'
import {adminBaseRoutePath} from '/@/router/static/adminBase'
import {useAdminInfo} from '/@/stores/adminInfo'
import {forEach} from "lodash-es";

window.requests = []
window.tokenRefreshing = false
const pendingMap = new Map()
const loadingInstance: LoadingInstance = {
	target: null,
	count: 0,
}

let isLogin = false

/**
 * 根据运行环境获取基础请求URL
 */
export const getUrl = (): string => {
	const value: string = import.meta.env.VITE_AXIOS_BASE_URL as string
	return value == 'getCurrentDomain' ? window.location.protocol + '//' + window.location.host : value
}

export const getImgUrl = (img: string): string => {
	return getUrl() + "/" + img
}

export const getVideoUrlArr = (img: string): string[] => {
	let a = img.split(",")
	a.forEach((item, key) => {
		a[key] = getUrl() + "/" + a[key]
	})
	return a
}

/**
 * 根据运行环境获取基础请求URL的端口
 */
export const getUrlPort = (): string => {
	const url = getUrl()
	return new URL(url).port
}

/**
 * 创建`Axios`
 * 默认开启`reductDataFormat(简洁响应)`,返回类型为`ApiPromise`
 * 关闭`reductDataFormat`,返回类型则为`AxiosPromise`
 */
function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequestConfig, options: Options = {}, loading: LoadingOptions = {}): T {
	const adminInfo = useAdminInfo()
	const Axios = axios.create({
		baseURL: getUrl(),
		timeout: 1000 * 50,
		headers: {},
		responseType: 'json',
	})

	options = Object.assign(
		{
			CancelDuplicateRequest: true, // 是否开启取消重复请求, 默认为 true
			loading: true, // 是否开启loading层效果, 默认为true
			reductDataFormat: true, // 是否开启简洁的数据结构响应, 默认为true
			showErrorMessage: true, // 是否开启接口错误信息展示,默认为true
			showCodeMessage: true, // 是否开启code不为0时的信息提示, 默认为true
			showSuccessMessage: false, // 是否开启code为0时的信息提示, 默认为false
			anotherToken: '', // 当前请求使用另外的用户token
		},
		options
	)

	// 请求拦截
	Axios.interceptors.request.use(
		(config) => {
			removePending(config)
			options.CancelDuplicateRequest && addPending(config)
			// 创建loading实例
			if (options.loading) {
				loadingInstance.count++
				if (loadingInstance.count === 1) {
					loadingInstance.target = ElLoading.service({
						target: document.querySelector(".loading")
					});
				}
			}

			const timestamp = Math.round(new Date().getTime() / 1000)
			//token 过期 兑换新token
			// if (timestamp > (adminInfo.expires_at - 60 * 10) && !isLogin && axiosConfig.url != "/system/login") {
			//     isLogin = true
			//     refreshToken()
			//         .then((res) => {
			//             if (res.code == 0) {
			//                 adminInfo.dataFill(res.data.userinfo)
			//             } else {
			//                 ElMessageBox.confirm(
			//                     "登录状态已过期，您可以继续留在该页面，或者重新登录",
			//                     "系统提示",
			//                     {
			//                         confirmButtonText: "重新登录",
			//                         cancelButtonText: "取消",
			//                         type: "warning"
			//                     }
			//                 )
			//                     .then(() => {
			//                         let routerPath = adminBaseRoutePath
			//
			//                         // 需要登录，清理 token，转到登录页
			//                         adminInfo.removeToken()
			//                         routerPath += '/login'
			//                         router.push({path: routerPath})
			//                     })
			//                     .catch(() => {
			//                         //message("取消重新登录", { type: "info" });
			//                     });
			//             }
			//             isLogin = false
			//         })
			//
			//
			// }


			// 自动携带token
			if (config.headers) {
				const token = adminInfo.getToken()

				if (token) (config.headers as anyObj).batoken = token

			}

			return config
		},
		(error) => {
			return Promise.reject(error)
		}
	)

	// 响应拦截
	Axios.interceptors.response.use(
		(response) => {
			removePending(response.config)
			options.loading && closeLoading(options) // 关闭loading

			if (response.config.responseType == 'json') {
				if (response.data && response.data.code !== 0) {
					if (response.data.code == 106) {
						let routerPath = adminBaseRoutePath

						// 需要登录，清理 token，转到登录页
						adminInfo.removeToken()
						routerPath += '/login'
						router.push({path: routerPath})
					}

					//未登录
					if (response.data.code == 101) {
						let routerPath = adminBaseRoutePath

						// 需要登录，清理 token，转到登录页
						adminInfo.removeToken()
						routerPath += '/login'
						router.push({path: routerPath})
					}

					if (options.showCodeMessage) {

						ElNotification({
							type: 'error',
							message: response.data.msg,
						})
					}


					// 自动跳转到路由name或path
					if (response.data.code == 302) {
						router.push({
							path: response.data.data.routePath ?? '',
							name: response.data.data.routeName ?? ''
						})
					}
					if (response.data.code == 303) {
						let routerPath = adminBaseRoutePath

						// 需要登录，清理 token，转到登录页
						if (response.data.data.type == 'need login') {
							adminInfo.removeToken()
							routerPath += '/login'
						}
						router.push({path: routerPath})
					}
					// code不等于0, 页面then内的具体逻辑就不执行了
					return Promise.reject(response.data)
				} else if (options.showSuccessMessage && response.data && response.data.code == 0) {
					ElNotification({
						message: response.data.msg ? response.data.msg : "操作成功",
						type: 'success',
					})
				}
			}
			return options.reductDataFormat ? response.data : response
		},
		(error) => {
			error.config && removePending(error.config)
			options.loading && closeLoading(options) // 关闭loading
			options.showErrorMessage && httpErrorStatusHandle(error) // 处理错误状态码
			return Promise.reject(error) // 错误继续返回给到具体页面
		}
	)
	return Axios(axiosConfig) as T
}

export default createAxios

/**
 * 处理异常
 * @param {*} error
 */
function httpErrorStatusHandle(error: any) {
	// 处理被取消的请求
	if (axios.isCancel(error)) return console.error("由于重复请求而自动取消:" + error.message)
	let message = ''
	if (error && error.response) {
		switch (error.response.status) {
			case 302:
				message = "接口重定向！"
				break
			case 400:
				message = '参数不正确！'
				break
			case 401:
				message = '您没有操作权限！'
				break
			case 403:
				message = '您没有操作权限！'
				break
			case 404:
				message = '请求地址时出错:' + error.response.config.url
				break
			case 408:
				message = '请求超时！'
				break
			case 409:
				message = '系统中已经存在相同的数据！'
				break
			case 500:
				message = '服务器内部错误！'
				break
			case 501:
				message = '服务未实现！'
				break
			case 502:
				message = '网关错误！'
				break
			case 503:
				message = '服务不可用！'
				break
			case 504:
				message = '该服务暂时不可用，请稍后再试！'
				break
			case 505:
				message = '不支持HTTP版本！'
				break
			default:
				message = '出现异常问题，请联系网站管理员！'
				break
		}
	}
	if (error.message.includes('timeout')) message = '网络请求超时！'
	if (error.message.includes('Network'))
		message = window.navigator.onLine ? '服务器异常！' : '您已断开连接！'

	ElNotification({
		type: 'error',
		message,
	})
}

/**
 * 关闭Loading层实例
 */
function closeLoading(options: Options) {
	if (options.loading && loadingInstance.count > 0) loadingInstance.count--
	if (loadingInstance.count === 0) {
		loadingInstance.target.close()
		loadingInstance.target = null
	}
}

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 */
function addPending(config: AxiosRequestConfig) {
	const pendingKey = getPendingKey(config)
	config.cancelToken =
		config.cancelToken ||
		new axios.CancelToken((cancel) => {
			if (!pendingMap.has(pendingKey)) {
				pendingMap.set(pendingKey, cancel)
			}
		})
}

/**
 * 删除重复的请求
 */
function removePending(config: AxiosRequestConfig) {
	const pendingKey = getPendingKey(config)
	if (pendingMap.has(pendingKey)) {
		const cancelToken = pendingMap.get(pendingKey)
		cancelToken(pendingKey)
		pendingMap.delete(pendingKey)
	}
}

/**
 * 生成每个请求的唯一key
 */
function getPendingKey(config: AxiosRequestConfig) {
	let {data} = config
	const {url, method, params, headers} = config
	if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
	return [
		url,
		method,
		headers && (headers as anyObj).batoken ? (headers as anyObj).batoken : '',
		headers && (headers as anyObj)['ba-user-token'] ? (headers as anyObj)['ba-user-token'] : '',
		JSON.stringify(params),
		JSON.stringify(data),
	].join('&')
}

/**
 * 根据请求方法组装请求数据/参数
 */
export function requestPayload(method: Method, data: anyObj) {
	if (method == 'GET') {
		return {
			params: data,
		}
	} else if (method == 'POST') {
		return {
			data: data,
		}
	}
}

interface LoadingInstance {
	target: any
	count: number
}

interface Options {
	// 是否开启取消重复请求, 默认为 true
	CancelDuplicateRequest?: boolean
	// 是否开启loading层效果, 默认为false
	loading?: boolean
	// 是否开启简洁的数据结构响应, 默认为true
	reductDataFormat?: boolean
	// 是否开启接口错误信息展示,默认为true
	showErrorMessage?: boolean
	// 是否开启code不为1时的信息提示, 默认为true
	showCodeMessage?: boolean
	// 是否开启code为1时的信息提示, 默认为false
	showSuccessMessage?: boolean
	// 当前请求使用另外的用户token
	anotherToken?: string
}

/*
 * 感谢掘金@橙某人提供的思路和分享
 * 本axios封装详细解释请参考：https://juejin.cn/post/6968630178163458084?share_token=7831c9e0-bea0-469e-8028-b587e13681a8#heading-27
 */
